package com.siyu.model.dispatch.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.siyu.basedata.modelparam.domain.ModelParam;
import com.siyu.basedata.modelparam.service.IModelParamService;
import com.siyu.basedata.wrprsrbsin.domain.WrpRsrBsin;
import com.siyu.basedata.wrprsrbsin.service.IWrpRsrBsinService;
import com.siyu.basedata.wrprsrhych.domain.WrpRsrHych;
import com.siyu.basedata.wrprsrhych.service.IWrpRsrHychService;
import com.siyu.basedata.wrprsrwlstcparrl.domain.Wrprsrwlstcparrl;
import com.siyu.basedata.wrprsrwlstcparrl.service.IwrprsrwlstcparrlService;
import com.siyu.basedata.xajresult.domain.XajResult;
import com.siyu.basedata.zqrlb.domain.ZqrlB;
import com.siyu.basedata.zqrlb.service.IZqrlBService;
import com.siyu.model.dispatch.dto.DispatchDto;
import com.siyu.model.dispatch.io.SingleDamInput;
import com.siyu.predict.dto.HisCalcDto;
import com.siyu.predict.dto.HypCalcDto;
import com.siyu.predict.service.PredictService;
import com.siyu.predict.utils.DataUtil;
import com.siyu.rehearsal.previewnd.domain.PreviewNd;
import com.siyu.rehearsal.previewnd.service.IPreviewNdService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Component
public class ParamMakeUtils {
    @Autowired
    private IWrpRsrBsinService wrpRsrBsinService;
    @Autowired
    private IWrpRsrHychService wrpRsrHychService;
    @Autowired
    private PredictService predictService;
    @Autowired
    private IwrprsrwlstcparrlService wrprsrwlstcparrlService;
    @Autowired
    private IZqrlBService zqrlBService;
    @Autowired
    private IPreviewNdService previewNdService;
    @Autowired
    private IModelParamService modelParamService;


    public static ParamMakeUtils paramMakeUtils;

    @PostConstruct
    public void init() {
        paramMakeUtils = this;
        paramMakeUtils.wrpRsrBsinService = this.wrpRsrBsinService;
        paramMakeUtils.wrpRsrHychService = this.wrpRsrHychService;
        paramMakeUtils.predictService = this.predictService;
        paramMakeUtils.wrprsrwlstcparrlService = this.wrprsrwlstcparrlService;
        paramMakeUtils.zqrlBService = this.zqrlBService;
        paramMakeUtils.modelParamService = this.modelParamService;
    }

    /**
     * @param dispatchDto
     */
    public SingleDamInput dispatchParaInit(DispatchDto dispatchDto) throws Exception {
        SingleDamInput input = new SingleDamInput();
        // 查询水库信息/特征信息
        WrpRsrBsin wrpRsrBsin = paramMakeUtils.wrpRsrBsinService.lambdaQuery().eq(WrpRsrBsin::getRscd, dispatchDto.getRscd()).one();
        WrpRsrHych wrpRsrHych = paramMakeUtils.wrpRsrHychService.lambdaQuery().eq(WrpRsrHych::getRscd, dispatchDto.getRscd()).one();
        input.setReservoirName(wrpRsrBsin.getRsnm());// 水库名称
        input.setReservoirID(wrpRsrBsin.getRscd());// 水库编码
        input.setStartTime(DateUtil.format(dispatchDto.getStartTime(), "yyyy-MM-dd HH:mm:ss")); // 开始时间
        input.setDeadLevel(wrpRsrHych.getDdwl()); // 死水位
        input.setNormalLevel(wrpRsrHych.getNrstlv());// 正常水位
        input.setFloodLevel(dispatchDto.getFloodLevel()); //防洪限制水位(防洪)
        input.setPeriodLength(3600);//时段长度
        input.setDiscretePointRate(7);// 计算离散倍数
        input.setQDWaterLevel(dispatchDto.getQdWaterLevel());//起调水位
        input.setDesignWaterLevel(dispatchDto.getDesignWaterLevel());// 设计洪水位
        input.setFCQrelease(dispatchDto.getFcQrelease()); //非常泄洪
        input.setXZQrelease(dispatchDto.getXzQrelease());//限制下泄
        Double downSafeQ = paramMakeUtils.modelParamService.lambdaQuery().eq(ModelParam::getRscd, dispatchDto.getRscd())
                .eq(ModelParam::getParamNum, "downSafeQ").one().getParamInitial();
        Double overQ = paramMakeUtils.modelParamService.lambdaQuery().eq(ModelParam::getRscd, dispatchDto.getRscd())
                .eq(ModelParam::getParamNum, "overQ").one().getParamInitial();
        input.setANQrelease(downSafeQ);//下游河道安全下泄
//        input.setANQrelease(115.51);//下游河道安全下泄
//        input.setCHQrelease(169.5);//敞泄流量
        input.setCHQrelease(overQ);//敞泄流量

        // 获取长系列来水过程,新安江模型计算
        HypCalcDto hypCalcDto = new HypCalcDto();
        hypCalcDto.setPr(dispatchDto.getAreaRains());
        hypCalcDto.setRscd(dispatchDto.getRscd());
        ArrayList<String> tms = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (Date tm : dispatchDto.getTms()) {
            String tm1 = sdf.format(tm);
            tms.add(tm1);
        }
        hypCalcDto.setTms(tms);

        BeanUtil.copyProperties(dispatchDto, hypCalcDto);
        hypCalcDto.setPr(dispatchDto.getAreaRains());

        /*=====================*/
        List<Double> preQ = null;
        if (dispatchDto.getPlanType().equals("情景")) {
            preQ = new ArrayList<Double>();
            QueryWrapper<PreviewNd> previewNdQueryWrapper = new QueryWrapper<>();
            previewNdQueryWrapper.select("qt_s")
                    .eq("plan_id", dispatchDto.getId()).orderByAsc("tm");
            List<PreviewNd> list = previewNdService.list(previewNdQueryWrapper);
            for (PreviewNd previewNd : list) {
                preQ.add(previewNd.getQtS());
            }
        } /*else if(dispatchDto.getPlanType().equals("假拟")){
            Map<Object, Object> map = paramMakeUtils.predictService.hypCalc(hypCalcDto);// 新安江模型计算
            List<XajResult> xajResults = Convert.toList(XajResult.class, map.get("xajData"));// 获取模型计算结果
            preQ = xajResults.stream().map(XajResult::getPreQ).collect(Collectors.toList());
        }*/
        else {
            Map<Object, Object> map = paramMakeUtils.predictService.hypCalc(hypCalcDto);// 新安江模型计算
            List<XajResult> xajResults = Convert.toList(XajResult.class, map.get("xajData"));// 获取模型计算结果
            preQ = xajResults.stream().map(XajResult::getPreQ).collect(Collectors.toList());
        }
        /*=====================*/
        /*=========================*/
        // 预演
     /*   ArrayList<String> tms = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (Date tm : dispatchDto.getTms()) {
            String tm1 = sdf.format(tm);
            tms.add(tm1);
        }
        List<Double> regulate = DataUtil.regulate(preQ,tms, dispatchDto.getRscd());
        List<Double> preZ = DataUtil.waterBalance(preQ, regulate, tms, dispatchDto.getRscd());
        Optional<Double> maxPreZ = preZ.stream()
                .max(Double::compare);

        // 检查是否找到了最大值
        if (maxPreZ.isPresent()) {
            System.out.println("最大值是: " + maxPreZ.get());
        } else {
            System.out.println("列表为空，没有最大值");
        }
        if (dispatchDto.getFloodLevel() > maxPreZ.get()){
            return null;
        }*/
        /*=========================*/

        input.setOperationRunoffData(preQ);
        input.setNumPeriod(preQ.size());// 根据流量更新时段数
        input.setFloodPeak(Collections.max(preQ));
        input.setFloodVolume(CommonUtils.getSumValue(preQ) * 3600 / 100000000);

        // 获取下游区间来水过程 这个地方要特殊考虑，直接是东江北干流来流 todo 设置为0
        input.setIntervalRunoffData(Collections.nCopies(preQ.size(), 0.0));

        // 获取各时段水位上限
        List<Double> UpLevelLimitArray = Collections.nCopies(preQ.size(), dispatchDto.getFloodLevel());
        input.setUpLevelLimitArray(UpLevelLimitArray);
        // 获取各时段水位下限
        // todo :死水位
        List<Double> DownLevelLimitArray = Collections.nCopies(preQ.size(), dispatchDto.getQdWaterLevel());
        ;
        input.setDownLevelLimitArray(DownLevelLimitArray);

        // 获取梯级各水库各时段下泄流量上限
        List<Double> UpQreleaseLimitArray = Collections.nCopies(preQ.size(), overQ);
        input.setUpQreleaseLimitArray(UpQreleaseLimitArray);
        // 获取梯级各水库各时段下泄流量下限
        List<Double> DownQreleaseLimitArray = Collections.nCopies(preQ.size(), 0.0);
        input.setDownQreleaseLimitArray(DownQreleaseLimitArray);

        // 获取各时段水库水量蒸发值
        List<Double> EvaLoss = Collections.nCopies(preQ.size(), 0.0);
        input.setEvaLoss(EvaLoss);

        // 库容曲线查询
        List<CurveDataItem> CurveLV = new ArrayList<>();
        List<Wrprsrwlstcparrl> wrprsrwlstcparrls = paramMakeUtils.wrprsrwlstcparrlService.lambdaQuery().eq(Wrprsrwlstcparrl::getRscd, dispatchDto.getRscd()).orderByAsc(Wrprsrwlstcparrl::getWl).list();
        for (Wrprsrwlstcparrl wrprsrwlstcparrl : wrprsrwlstcparrls) {
            CurveDataItem curveDataItem = new CurveDataItem(wrprsrwlstcparrl.getWl(), wrprsrwlstcparrl.getStcp() / 10000);
            CurveLV.add(curveDataItem);
        }
        input.setCurveLV(CurveLV);

        // 获取水库泄流能力曲线
        List<CurveDataItem> CurveLQ = new ArrayList<>();
        paramMakeUtils.zqrlBService.lambdaQuery().eq(ZqrlB::getRscd, dispatchDto.getRscd()).list().forEach(zqrlB -> {
            CurveDataItem curveDataItem = new CurveDataItem(zqrlB.getZ(), zqrlB.getQ());
            CurveLQ.add(curveDataItem);
        });
        input.setCurveLQ(CurveLQ);
        return input;
    }
}
